package com.wowoai.common.factoy;

import com.wowoai.utils.IdGeneratorUtil;
import org.springframework.stereotype.Component;

@Component
public class SnowflakeIdGenerator {
    // 起始的时间戳，2018-01-01 00:00:00
    private static final long START_TIMESTAMP = 1514736000000L;
    private static long dataCenterId = 1; // 数据中心
    private static long machineId =1; // 机器标识
    // 每一部分占用的位数
    private static final long SEQUENCE_BIT = 12; // 序列号占用的位数
    private static final long MACHINE_BIT = 5; // 机器标识占用的位数
    private static final long DATA_CENTER_BIT = 5; // 数据中心占用的位数

    // 每一部分的最大值
    private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);
    private static final long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);
    private static final long MAX_DATA_CENTER_NUM = ~(-1L << DATA_CENTER_BIT);

    // 每一部分向左的位移
    private static final long MACHINE_LEFT = SEQUENCE_BIT;
    private static final long DATA_CENTER_LEFT = MACHINE_LEFT + MACHINE_BIT;
    private static final long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;

    private long sequence = 0L; // 序列号
    private long lastTimestamp = -1L; // 上一次时间戳

    public SnowflakeIdGenerator() {
        if (dataCenterId > MAX_DATA_CENTER_NUM || dataCenterId < 0) {
            throw new IllegalArgumentException("Data center ID can't be greater than " + MAX_DATA_CENTER_NUM + " or less than 0");
        }

        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("Machine ID can't be greater than " + MAX_MACHINE_NUM + " or less than 0");
        }
        IdGeneratorUtil.setSnowflakeIdGenerator(this);
    }

    // 生成当前时间戳
    private long getCurrentTimestamp() {
        return System.currentTimeMillis();
    }

    // 获取下一个序列号
    private synchronized long getNextSequence() {
        if (sequence >= MAX_SEQUENCE) {
            sequence = 0L;
        }

        return sequence++;
    }

    // 获取当前的时间戳，并检查时间戳是否比上一次获取的时间戳大
    private synchronized long getNextTimestamp() {
        long timestamp = getCurrentTimestamp();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate ID");
        }

        if (timestamp == lastTimestamp) {
            // 如果一个毫秒内生成的序列号已经达到了最大值，则等待下一毫秒再生成序列号
            return (lastTimestamp = timestamp) + 1;
        } else {
            return lastTimestamp = timestamp;
        }
    }

    // 生成下一个全局唯一的 ID
    public synchronized long nextId() {
        long timestamp = getNextTimestamp();

        // 生成序列号
        long sequence = getNextSequence();

        // 组装全局唯一 ID
        return ((timestamp - START_TIMESTAMP) << TIMESTAMP_LEFT) | (dataCenterId << DATA_CENTER_LEFT) | (machineId << MACHINE_LEFT) | sequence;
    }
}
